using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;

namespace PDUConverter.SmartMessaging
{
    /// <summary>
    /// Creates messages based on Nokia's Smart Messaging specification.
    /// </summary>
    public class SmartMessageFactory
    {
        /// <summary>
        /// Represents an empty operator logo that can be used to remove an operator logo.
        /// It depends on the phone model whether it works.
        /// </summary>
        //public static readonly byte[] EmptyOperatorLogo = CreateOperatorLogo(new OtaBitmap(null), "000", "00");
        private static byte refNumber = 1;

        /// <summary>
        /// Calculates the next reference number.
        /// </summary>
        /// <remarks>Returns the current number and then increments it by one.
        /// If the new number would exceed 255, it it reset to 1.</remarks>
        /// <returns>The next reference number.</returns>
        protected static byte CalcNextRefNumber()
        {
            byte refNumber;
            lock (typeof(SmartMessageFactory))
            {
                refNumber = SmartMessageFactory.refNumber;
                if (SmartMessageFactory.refNumber == 0xff)
                {
                    SmartMessageFactory.refNumber = 1;
                    return refNumber;
                }
                SmartMessageFactory.refNumber = (byte) (SmartMessageFactory.refNumber + 1);
            }
            return refNumber;
        }

        /// <summary>
        /// Creates a concatenated text message.
        /// </summary>
        /// <param name="userDataText">The message text.</param>
        /// <param name="destinationAddress">The message's destination address.</param>
        /// <returns>A set of <see cref="T:GsmComm.PduConverter.SmsPdu" /> objects that represent the message.</returns>
        /// <remarks><para>The userDataText is converted to the 7-bit default alphabet automatically. The resulting
        /// string must not exceed 160 characters. Therefore, if 7-bit characters occupy more than
        /// one character, the userDataText must be shorter than 160 characters.</para>
        /// <para>If no concatenation is necessary, the <see cref="T:GsmComm.PduConverter.SmsPdu" /> class handles the encoding
        /// as if it was used directly.</para>
        /// </remarks>
        /// <exception cref="T:System.ArgumentException"><para>userDataText is so long that it would create more than 255 message parts.</para></exception>
        public static SmsSubmitPdu[] CreateConcatTextMessage(string userDataText, string destinationAddress)
        {
            return CreateConcatTextMessage(userDataText, destinationAddress, string.Empty);
        }

        /// <summary>
        /// Creates a concatenated text message.
        /// </summary>
        /// <param name="userDataText">The message text.</param>
        /// <param name="destinationAddress">The message's destination address.</param>
        /// <param name="smscAddress">The service center (SMSC) address. Can be an empty string.</param>
        /// <returns>A set of <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> objects that represent the message.</returns>
        /// <remarks><para>The userDataText is converted to the GSM 7-bit default alphabet automatically.</para>
        /// <para>If no concatenation is necessary, the <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> class handles the encoding
        /// as if it was used directly.</para>
        /// </remarks>
        /// <exception cref="T:System.ArgumentException"><para>userDataText is so long that it would create more than 255 message parts.</para></exception>
        public static SmsSubmitPdu[] CreateConcatTextMessage(string userDataText, string destinationAddress, string smscAddress)
        {
            string str = TextDataConverter.StringTo7Bit(userDataText);
            if (str.Length > 160)
            {
                int num4;
                byte num = 7;
                byte num2 = (byte) ((((double) num) / 7.0) * 8.0);
                StringCollection strings = new StringCollection();
                for (int i = 0; i < str.Length; i += num4)
                {
                    string str2 = string.Empty;
                    num4 = 0;
                    if ((str.Length - i) >= (160 - num2))
                    {
                        num4 = 160 - num2;
                    }
                    else
                    {
                        num4 = str.Length - i;
                    }
                    str2 = str.Substring(i, num4);
                    strings.Add(str2);
                }
                if (strings.Count > 0xff)
                {
                    throw new ArgumentException("A concatenated message must not have more than 255 parts.", "userDataText");
                }
                ArrayList list = new ArrayList();
                byte referenceNumber = CalcNextRefNumber();
                byte currentNumber = 0;
                for (int j = 0; j < strings.Count; j++)
                {
                    currentNumber = (byte) (currentNumber + 1);
                    ConcatMessageElement element = new ConcatMessageElement(referenceNumber, (byte) strings.Count, currentNumber);
                    byte[] buffer = new byte[num];
                    int index = 0;
                    buffer[index++] = (byte) (element.ToByteArray().Length + 1);
                    element.ToByteArray().CopyTo(buffer, index);
                    index += element.ToByteArray().Length;
                    buffer[index++] = 0;
                    int num9 = num2 + strings[j].Length;
                    byte[] buffer2 = TextDataConverter.SeptetsToOctetsInt(strings[j]);
                    byte[] buffer3 = new byte[buffer.Length + buffer2.Length];
                    buffer.CopyTo(buffer3, 0);
                    buffer2.CopyTo(buffer3, index);
                    SmsSubmitPdu pdu = new SmsSubmitPdu();
                    pdu.MessageFlags.UserDataHeaderPresent = true;
                    pdu.SmscAddress = smscAddress;
                    pdu.DestinationAddress = destinationAddress;
                    pdu.SetUserData(buffer3, (byte) num9);
                    list.Add(pdu);
                }
                SmsSubmitPdu[] array = new SmsSubmitPdu[list.Count];
                list.CopyTo(array, 0);
                return array;
            }
            return new SmsSubmitPdu[] { new SmsSubmitPdu(userDataText, destinationAddress, smscAddress) };
        }

        /// <summary>
        /// Creates a concatenated Unicode text message.
        /// </summary>
        /// <param name="userDataText">The message text.</param>
        /// <param name="destinationAddress">The message's destination address.</param>
        /// <returns>A set of <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> objects that represent the message.</returns>
        /// <remarks><para>The userDataText is converted to UCS2 (Unicode) automatically.</para>
        /// <para>If no concatenation is necessary, the <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> class handles the encoding
        /// as if it was used directly.</para>
        /// </remarks>
        /// <exception cref="T:System.ArgumentException"><para>userDataText is so long that it would create more than 255 message parts.</para></exception>
        public static SmsSubmitPdu[] CreateConcatUnicodeTextMessage(string userDataText, string destinationAddress)
        {
            return CreateConcatUnicodeTextMessage(userDataText, destinationAddress, string.Empty);
        }

        /// <summary>
        /// Creates a concatenated Unicode text message.
        /// </summary>
        /// <param name="userDataText">The message text.</param>
        /// <param name="destinationAddress">The message's destination address.</param>
        /// <param name="smscAddress">The service center (SMSC) address. Can be an empty string.</param>
        /// <returns>A set of <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> objects that represent the message.</returns>
        /// <remarks><para>The userDataText is converted to UCS2 (Unicode) automatically.</para>
        /// <para>If no concatenation is necessary, the <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> class handles the encoding
        /// as if it was used directly.</para>
        /// </remarks>
        /// <exception cref="T:System.ArgumentException"><para>userDataText is so long that it would create more than 255 message parts.</para></exception>
        public static SmsSubmitPdu[] CreateConcatUnicodeTextMessage(string userDataText, string destinationAddress, string smscAddress)
        {
            if (userDataText.Length > 70)
            {
                int num3;
                byte num = 7;
                StringCollection strings = new StringCollection();
                for (int i = 0; i < userDataText.Length; i += num3)
                {
                    string str = string.Empty;
                    num3 = 0;
                    if ((userDataText.Length - i) >= (70 - num))
                    {
                        num3 = 70 - num;
                    }
                    else
                    {
                        num3 = userDataText.Length - i;
                    }
                    str = userDataText.Substring(i, num3);
                    strings.Add(str);
                }
                if (strings.Count > 0xff)
                {
                    throw new ArgumentException("A concatenated message must not have more than 255 parts.", "userDataText");
                }
                ArrayList list = new ArrayList();
                byte referenceNumber = CalcNextRefNumber();
                byte currentNumber = 0;
                for (int j = 0; j < strings.Count; j++)
                {
                    currentNumber = (byte) (currentNumber + 1);
                    ConcatMessageElement element = new ConcatMessageElement(referenceNumber, (byte) strings.Count, currentNumber);
                    byte[] buffer = new byte[num];
                    int index = 0;
                    buffer[index++] = (byte) (element.ToByteArray().Length + 1);
                    element.ToByteArray().CopyTo(buffer, index);
                    index += element.ToByteArray().Length;
                    buffer[index++] = 0;
                    byte[] bytes = Encoding.BigEndianUnicode.GetBytes(strings[j]);
                    byte[] buffer3 = new byte[buffer.Length + bytes.Length];
                    buffer.CopyTo(buffer3, 0);
                    bytes.CopyTo(buffer3, index);
                    int length = buffer3.Length;
                    SmsSubmitPdu pdu = new SmsSubmitPdu();
                    pdu.MessageFlags.UserDataHeaderPresent = true;
                    pdu.SmscAddress = smscAddress;
                    pdu.DestinationAddress = destinationAddress;
                    pdu.DataCodingScheme = 8;
                    pdu.SetUserData(buffer3, (byte) length);
                    list.Add(pdu);
                }
                SmsSubmitPdu[] array = new SmsSubmitPdu[list.Count];
                list.CopyTo(array, 0);
                return array;
            }
            return new SmsSubmitPdu[] { new SmsSubmitPdu(userDataText, destinationAddress, smscAddress, 8) };
        }

        /// <summary>
        /// Creates an operator logo.
        /// </summary>
        /// <param name="otaBitmap">The OTA bitmap to use as the logo. Maximum size is 72x14 pixels.</param>
        /// <param name="mobileCountryCode">MCC. The operator's country code. Must be 3 digits long.</param>
        /// <param name="mobileNetworkCode">MNC. The operator's network code. Must be 2 digits long.</param>
        /// <returns>A byte array containing the generated operator logo.</returns>
        /// <exception cref="T:System.ArgumentNullException">otaBitmap is null.</exception>
        /// <exception cref="T:System.ArgumentException"><para>mobileCountryCode is not 3 digits long.</para><para> -or- </para>
        /// <para>mobileNetworkCode is not 2 digits long.</para>
        /// <para> -or- </para><para>The bitmap is larger than 72x14 pixels.</para>
        /// </exception>
        public static byte[] CreateOperatorLogo(OtaBitmap otaBitmap, string mobileCountryCode, string mobileNetworkCode)
        {
            if (otaBitmap == null)
            {
                throw new ArgumentNullException("otaBitmap");
            }
            if ((otaBitmap.Width > 0x48) || (otaBitmap.Height > 14))
            {
                string[] strArray = new string[] { "Bitmaps used as operator logos must not be larger than ", 0x48.ToString(), "x", 14.ToString(), " pixels." };
                throw new ArgumentException(string.Concat(strArray));
            }
            if (mobileCountryCode.Length != 3)
            {
                throw new ArgumentException("mobileCountryCode must be 3 digits long.", "mobileCountryCode");
            }
            if (mobileNetworkCode.Length != 2)
            {
                throw new ArgumentException("mobileNetworkCode must be 2 digits long.", "mobileNetworkCode");
            }
            byte num = 0x30;
            byte[] buffer = Calc.HexToInt(BcdWorker.EncodeSemiOctets(mobileCountryCode.PadRight(4, 'F')));
            byte[] buffer2 = Calc.HexToInt(BcdWorker.EncodeSemiOctets(mobileNetworkCode.PadRight(2, 'F')));
            int num2 = ((1 + buffer.Length) + buffer2.Length) + 1;
            int index = 0;
            byte[] array = new byte[num2];
            array[index++] = num;
            buffer.CopyTo(array, index);
            index += buffer.Length;
            buffer2.CopyTo(array, index);
            index += buffer2.Length;
            array[index++] = 10;
            byte[] buffer4 = otaBitmap.ToByteArray();
            byte[] buffer5 = new byte[array.Length + buffer4.Length];
            array.CopyTo(buffer5, 0);
            buffer4.CopyTo(buffer5, index);
            return buffer5;
        }

        /// <summary>
        /// Creates an operator logo message.
        /// </summary>
        /// <param name="operatorLogo">The operator logo. Use <see cref="M:GsmComm.PduConverter.SmartMessaging.SmartMessageFactory.CreateOperatorLogo(GsmComm.PduConverter.SmartMessaging.OtaBitmap,System.String,System.String)" /> to create one.</param>
        /// <param name="destinationAddress">The message's destination address.</param>
        /// <param name="smscAddress">The service center (SMSC) address. Can be an empty string.</param>
        /// <returns>A set of <see cref="T:GsmComm.PduConverter.SmsSubmitPdu" /> objects that represent the message.</returns>
        /// <exception cref="T:System.ArgumentNullException">operatorLogo is null.</exception>
        /// <exception cref="T:System.ArgumentException"><para>operatorLogo is an empty array.</para>
        /// <para> -or- </para><para>destinationAddress is an empty string.</para>
        /// <para> -or- </para><para>operatorLogo is so big that it would create more than 255 message parts.</para></exception>
        public static SmsSubmitPdu[] CreateOperatorLogoMessage(byte[] operatorLogo, string destinationAddress, string smscAddress)
        {
            if (operatorLogo == null)
            {
                throw new ArgumentNullException("operatorLogo");
            }
            if (operatorLogo.Length == 0)
            {
                throw new ArgumentException("operatorLogo must not be an empty array.", "operatorLogo");
            }
            PortAddressElement element = new PortAddressElement("1582", "0000");
            byte length = (byte) element.ToByteArray().Length;
            int num2 = length + 1;
            bool flag = operatorLogo.Length > (140 - num2);
            if (flag)
            {
                ConcatMessageElement element2 = new ConcatMessageElement(0, 0, 0);
                length = (byte) (element.ToByteArray().Length + element2.ToByteArray().Length);
                num2 = length + 1;
            }
            ArrayList list = new ArrayList();
            int sourceIndex = 0;
            byte totalMessages = (byte) Math.Ceiling((double) (((double) operatorLogo.Length) / ((double) (140 - num2))));
            if (list.Count > 0xff)
            {
                throw new ArgumentException("A concatenated message must not have more than 255 parts.", "operatorLogo");
            }
            byte referenceNumber = 1;
            if (flag)
            {
                referenceNumber = CalcNextRefNumber();
            }
            for (byte i = 1; i <= totalMessages; i = (byte) (i + 1))
            {
                int num7 = 0;
                if ((operatorLogo.Length - sourceIndex) >= (140 - num2))
                {
                    num7 = 140 - num2;
                }
                else
                {
                    num7 = operatorLogo.Length - sourceIndex;
                }
                byte[] buffer = new byte[num2];
                int index = 0;
                buffer[index++] = length;
                element.ToByteArray().CopyTo(buffer, index);
                index += element.ToByteArray().Length;
                if (flag)
                {
                    ConcatMessageElement element3 = new ConcatMessageElement(referenceNumber, totalMessages, i);
                    element3.ToByteArray().CopyTo(buffer, index);
                    index += element3.ToByteArray().Length;
                }
                byte[] buffer2 = new byte[buffer.Length + num7];
                buffer.CopyTo(buffer2, 0);
                Array.Copy(operatorLogo, sourceIndex, buffer2, index, num7);
                SmsSubmitPdu pdu = new SmsSubmitPdu();
                pdu.MessageFlags.UserDataHeaderPresent = true;
                pdu.DataCodingScheme = 0x15;
                pdu.SmscAddress = smscAddress;
                pdu.DestinationAddress = destinationAddress;
                pdu.SetUserData(buffer2, (byte) buffer2.Length);
                list.Add(pdu);
                sourceIndex += num7;
            }
            SmsSubmitPdu[] array = new SmsSubmitPdu[list.Count];
            list.CopyTo(array, 0);
            return array;
        }
    }
}